Rejecting non-numeric input
When improving the contact form, we discussed some input validation
techniques. With JavaScript, we verified that what the user typed
matched what we were expecting so that we could provide feedback before
the form was even sent to the server. Now, we'll examine the counterpart
to input validation called input masking.
Input validation checks what
the user has typed against some criteria for valid inputs. Input masking
applies criteria to the entries while they are being typed in the first
place, and simply disallows invalid keystrokes. In our shopping-cart
form, for example, the input fields must contain only numbers. Input
masking code can cause any key that is not a number to do nothing when
one of these fields is in focus:
$('td.quantity input').keypress(function(event) {
if (event.which && (event.which < 48 ||
event.which > 57)) {
event.preventDefault();
}
});
When catching keystrokes for our search field's auto-completion function, we watched the keyup event. This allowed us to examine the .keyCode property of the event which told us which key on the keyboard was pressed. Here, we observe the keypress event instead. This event does not have a .keyCode property, but instead offers the .which property. This property reports the actual ASCII character that is represented by the keystroke that just occurred.
If the keystroke results in a character (that is, it is not an arrow key, delete, or some other editing function) and that character is not in the range of ASCII codes that represent numerals, then we call .preventDefault()
on the event. As we have seen before, this stops the browser from
acting on the event; in this case, that means that the character is
never inserted into the field. Now, the quantity fields can accept only
numbers.
Numeric calculations
Now, we'll move on to some manipulation of the actual numbers the user will enter in the shopping cart form. We have a Recalculate
button on the form, which would cause the form to be submitted to the
server, where new totals can be calculated and the form can be presented
again to the user. This requires a round trip that is not necessary,
though; all of this work can be done on the browser side using jQuery.
The simplest calculation on this form is for the cell in the Shipping
row that displays the total quantity of items ordered. When the user
modifies a quantity in one of the rows, we want to add up all of the
entered values to produce a new total and display this total in the
cell:
Var $quantities = $('td.quantity input');
$quantities.change(function() {
var totalQuantity = 0;
$quantities.each(function() {
var quantity = parseInt(this.value);
totalQuantity += quantity;
});
$('tr.shipping td.quantity').text(String(totalQuantity));
});
We have several choices for which event to watch for this recalculation operation. We could observe the keypress event, and fire the recalculation with each keystroke. We could also observe the blur
event, which is triggered each time the user leaves the field. Here, we
can be a little more conservative with CPU usage, though, and only
perform our calculations when the change
event is triggered. This way, we recalculate the totals only if the
user leaves the field with a different value than it had before.
The total quantity is calculated using a simple .each() loop. The .value property of a field will report the string representation of the field's value, so we use the built-in parseInt()
function to convert this into an integer for our calculation. This
practice can avoid strange situations in which addition is interpreted
as string concatenation, since the two operations use the same symbol.
Conversely, we need a string to pass to jQuery's .text() method when displaying the calculation's result, so we use the String() function to build a new one using our calculated total quantity.
Changing a quantity now updates the total automatically: